<template>
  <view
    v-if="visible"
    class="hb-fixed hb-left-0 hb-top-0 hb-w-screen hb-h-screen hb-z-999"
    @click="handleStepClick"
  >
    <!-- 使用循环渲染所有遮罩和圆角 -->
    <template v-for="(mask, index) in masks" :key="index">
      <view
        class="hb-absolute hb-transition-all hb-duration-300 hb-ease-in-out"
        :class="mask.type === 'mask' ? 'hb-bg-black hb-opacity-50' : ''"
        :style="getMaskStyle(mask)"
      ></view>
    </template>

    <view
      class="hb-p-3 hb-relative hb-bg-primary hb-rounded-xl hb-absolute hb-transition-all hb-duration-300"
      :style="{
        width: tipsViewWidth + 'px',
        top: getTipsTop(),
        left: getTipsLeft() + 'px',
        zIndex: 3,
      }"
    >
      <!-- 上箭头，在提示框显示在高亮区域下方时显示 -->
      <view
        v-if="!shouldShowOnTop()"
        class="hb-w-0 hb-h-0 hb-absolute hb--top-2 hb-border-l-[20rpx] hb-border-r-[20rpx] hb-border-b-[20rpx] hb-border-solid hb-border-l-transparent hb-border-r-transparent hb-border-b-primary hb-transition-all hb-duration-300"
        :style="{
          left: getTrianglePosition() + 'px',
        }"
      ></view>

      <!-- 下箭头，在提示框显示在高亮区域上方时显示 -->
      <view
        v-if="shouldShowOnTop()"
        class="hb-w-0 hb-h-0 hb-absolute hb--bottom-2 hb-border-l-[20rpx] hb-border-r-[20rpx] hb-border-t-[20rpx] hb-border-solid hb-border-l-transparent hb-border-r-transparent hb-border-t-primary hb-transition-all hb-duration-300"
        :style="{
          left: getTrianglePosition() + 'px',
        }"
      ></view>

      <TmText
        _class="hb-font-bold hb-mb-1"
        :label="getTipsViewTitle"
        color="#fff"
        :font-size="32"
      />
      <TmText :label="currentStep.description" color="#fff" :font-size="28" />
    </view>
  </view>
</template>

<script setup lang="ts">
  import { GuideStep, GuideType, useGuideStore } from '@/store/modules/guide';
  import { CSSProperties } from 'vue';
  import { boundingClientRect } from '.';

  const props = defineProps<{
    stepsNumber: number;
    type: GuideType;
  }>();

  const visible = ref(false);
  const guideStore = useGuideStore();
  const { homeSteps, chatSteps } = storeToRefs(guideStore);

  const steps = computed(() => {
    return props.type === GuideType.HOME ? homeSteps.value : chatSteps.value;
  });

  const stepIndex = ref(0);

  const getStepStyle = async () => {
    for (const step of steps.value) {
      if (step.nodeInfo) {
        const res = await boundingClientRect(step.nodeInfo.selector, step.nodeInfo.ins);
        step.style = {
          width: res.width ?? 0,
          height: res.height ?? 0,
          left: res.left ?? 0,
          top: res.top ?? 0,
        };
      }
    }
  };

  watch(
    () => steps.value,
    async (val) => {
      if (val.length > 0 && val.length >= props.stepsNumber && !visible.value) {
        await getStepStyle();
        visible.value = true;
        stepIndex.value = 0;
      }
    },
    {
      immediate: true,
      deep: true,
    },
  );

  const currentStep = computed(() => {
    return steps.value[stepIndex.value] as Required<GuideStep>;
  });

  const getTipsViewTitle = computed(() => {
    return currentStep.value.title + '（' + (stepIndex.value + 1) + '/' + steps.value.length + '）';
  });

  function handleStepClick() {
    if (stepIndex.value >= steps.value.length - 1) {
      guideStore.clearGuide(props.type);
      visible.value = false;
      return;
    }

    stepIndex.value++;
  }

  const windowInfo = uni.getWindowInfo();
  const tipsViewWidth = 232;
  const padding = 8; // 镂空区域周围的padding
  const cornerSize = 8; // 圆角大小

  // 定义遮罩类型
  type MaskType = 'mask' | 'corner';

  // 定义遮罩位置
  type MaskPosition =
    | 'top'
    | 'left'
    | 'right'
    | 'bottom'
    | 'topLeft'
    | 'topRight'
    | 'bottomLeft'
    | 'bottomRight';

  // 定义遮罩接口
  interface Mask {
    type: MaskType;
    position: MaskPosition;
  }

  // 定义所有遮罩
  const masks = computed<Mask[]>(() => [
    { type: 'mask', position: 'top' },
    { type: 'mask', position: 'left' },
    { type: 'mask', position: 'right' },
    { type: 'mask', position: 'bottom' },
    { type: 'corner', position: 'topLeft' },
    { type: 'corner', position: 'topRight' },
    { type: 'corner', position: 'bottomLeft' },
    { type: 'corner', position: 'bottomRight' },
  ]);

  // 计算遮罩样式
  function getMaskStyle(mask: Mask): CSSProperties {
    const { width, height, left, top } = currentStep.value.style;

    switch (mask.position) {
      case 'top':
        return {
          left: '0',
          top: '0',
          width: windowInfo.windowWidth + 'px',
          height: Math.max(0, top - padding) + 'px',
        };
      case 'left':
        return {
          left: '0',
          top: top - padding + 'px',
          width: Math.max(0, left - padding) + 'px',
          height: height + padding * 2 + 'px',
        };
      case 'right':
        return {
          left: left + width + padding + 'px',
          top: top - padding + 'px',
          width: Math.max(0, windowInfo.windowWidth - left - width - padding) + 'px',
          height: height + padding * 2 + 'px',
        };
      case 'bottom':
        return {
          left: '0',
          top: top + height + padding + 'px',
          width: windowInfo.windowWidth + 'px',
          height: Math.max(0, windowInfo.windowHeight - top - height - padding) + 'px',
        };
      case 'topLeft':
        return {
          left: left - padding + 'px',
          top: top - padding + 'px',
          width: cornerSize + 'px',
          height: cornerSize + 'px',
          background:
            'radial-gradient(circle at 100% 100%, transparent ' +
            cornerSize +
            'px, rgba(0, 0, 0, 0.5) 0)',
        };
      case 'topRight':
        return {
          left: left + width + padding - cornerSize + 'px',
          top: top - padding + 'px',
          width: cornerSize + 'px',
          height: cornerSize + 'px',
          background:
            'radial-gradient(circle at 0% 100%, transparent ' +
            cornerSize +
            'px, rgba(0, 0, 0, 0.5) 0)',
        };
      case 'bottomLeft':
        return {
          left: left - padding + 'px',
          top: top + height + padding - cornerSize + 'px',
          width: cornerSize + 'px',
          height: cornerSize + 'px',
          background:
            'radial-gradient(circle at 100% 0%, transparent ' +
            cornerSize +
            'px, rgba(0, 0, 0, 0.5) 0)',
        };
      case 'bottomRight':
        return {
          left: left + width + padding - cornerSize + 'px',
          top: top + height + padding - cornerSize + 'px',
          width: cornerSize + 'px',
          height: cornerSize + 'px',
          background:
            'radial-gradient(circle at 0% 0%, transparent ' +
            cornerSize +
            'px, rgba(0, 0, 0, 0.5) 0)',
        };
      default:
        return {};
    }
  }

  /** 计算三角形的位置 */
  function getTrianglePosition() {
    const { width, left } = currentStep.value.style;
    const windowWidth = windowInfo.windowWidth;
    const triangleWidth = 20; // 三角形宽度(rpx)
    const centerPoint = left + width / 2; // 高亮区域的中心点
    const screenCenter = windowWidth / 2; // 屏幕中心点
    const centerThreshold = windowWidth * 0.1; // 判定为中心的阈值范围（屏幕宽度的10%）

    // 情况1：高亮区域宽度超过屏幕一半，三角形居中
    if (width > windowWidth / 2) {
      return tipsViewWidth / 2 - triangleWidth / 2;
    }

    // 情况2：高亮区域在屏幕中间区域，三角形居中
    if (Math.abs(centerPoint - screenCenter) < centerThreshold) {
      return tipsViewWidth / 2 - triangleWidth / 2;
    }

    // 情况3：高亮区域靠近屏幕右侧
    if (centerPoint > screenCenter) {
      // 三角形靠右（保留20rpx边距）
      return tipsViewWidth - triangleWidth * 2;
    }

    // 情况4：高亮区域靠近屏幕左侧
    return triangleWidth; // 三角形靠左（保留20rpx边距）
  }

  /** 判断提示框是否应该显示在高亮区域上方 */
  function shouldShowOnTop() {
    const { top, height } = currentStep.value.style;
    const bottomSpace = windowInfo.windowHeight - top - height;
    const minRequiredSpace = 120; // 提示框所需的最小空间（根据实际需要调整）

    // 如果底部空间不足且顶部空间足够，则在顶部显示
    return bottomSpace < minRequiredSpace && top > minRequiredSpace;
  }

  /** 计算提示框的位置 */
  function getTipsLeft() {
    const { width, left } = currentStep.value.style;
    const windowWidth = windowInfo.windowWidth;
    let calculatedLeft;

    if (width > windowWidth / 2) {
      calculatedLeft = left + width / 2 - tipsViewWidth / 2;
    } else {
      calculatedLeft = left + width / 2 - tipsViewWidth / 2;
    }

    // 处理左边界溢出
    if (calculatedLeft < 10) {
      calculatedLeft = 10; // 保留10px边距
    }

    // 处理右边界溢出
    if (calculatedLeft + tipsViewWidth > windowWidth - 10) {
      calculatedLeft = windowWidth - tipsViewWidth - 10; // 保留10px边距
    }

    return calculatedLeft;
  }

  /** 计算提示框的顶部位置 */
  function getTipsTop() {
    const { top, height } = currentStep.value.style;

    if (shouldShowOnTop()) {
      // 显示在高亮区域上方，增加间距
      return top - 32 - 80 + 'px'; // 80是提示框的大致高度，增加间距至32px
    } else {
      // 显示在高亮区域下方，增加间距
      return top + height + 32 + 'px'; // 增加间距至32px
    }
  }
</script>

<style lang="scss" scoped></style>
